package com.znow.admin.system.security.service.impl;

import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.znow.admin.dao.entity.sys.SysPermissionEntity;
import com.znow.admin.dao.entity.sys.SysRolePermissionRelationEntity;
import com.znow.admin.dao.entity.sys.SysUserRoleEntity;
import com.znow.admin.dao.mapper.sys.SysPermissionMapper;
import com.znow.admin.system.security.enums.PermissionTypeEnums;
import com.znow.admin.system.security.model.convert.ComponentConvert;
import com.znow.admin.system.security.model.convert.SysPermissionsConvert;
import com.znow.admin.system.security.model.dto.PermissionsTreeDTO;
import com.znow.admin.system.security.model.res.PermissionPageRequest;
import com.znow.admin.system.security.model.res.PermissionRequest;
import com.znow.admin.system.security.model.vo.component.ComponentVO;
import com.znow.admin.system.security.service.SysPermissionsService;
import com.znow.admin.system.security.service.SysRoleService;
import com.znow.common.exception.BizException;
import com.znow.common.exception.ParamsException;
import com.znow.common.model.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 系统权限接口实现类
 *
 * @author Nemo
 * @date 2022/11/01
 */
@Slf4j
@Service
public class SysPermissionServiceImpl implements SysPermissionsService {

    @Resource
    private SysPermissionMapper sysPermissionMapper;

    @Autowired
    private SysRoleService sysRoleService;

    @Override
    public List<PermissionsTreeDTO> getPermissionsByUserId(Long userId) {
        Assert.notNull(userId, "用户ID不能为空！");
        // 查询出当前用户拥有的所有角色
        List<SysUserRoleEntity> roleEntityList = sysRoleService.getRoleListByUserId(userId);
        if (CollectionUtils.isEmpty(roleEntityList)) {
            return Lists.newArrayList();
        }
        List<Long> userRoleIds = roleEntityList.stream().map(SysUserRoleEntity::getRoleId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(userRoleIds)) {
            return Lists.newArrayList();
        }
        // 根据角色查询出所有权限数据
        List<SysRolePermissionRelationEntity> sysRolePermissions = sysPermissionMapper
                .selectPermissionByRoleIds(userRoleIds);
        if (CollectionUtils.isEmpty(sysRolePermissions)) {
            return Lists.newArrayList();
        }
        return SysPermissionsConvert.INSTANCE.toPermissionsDTOListByRelation(sysRolePermissions);
    }

    @Override
    public List<PermissionsTreeDTO> getPermissionsByParentId(Long parentId) {
        Assert.notNull(parentId, "父类ID不能为空！");
        final List<SysPermissionEntity> dbFirstPermissions = sysPermissionMapper
                .selectPermissionByParentId(parentId);
        if (CollectionUtils.isEmpty(dbFirstPermissions)) {
            return Lists.newArrayList();
        }
        return SysPermissionsConvert.INSTANCE.toPermissionsDTOList(dbFirstPermissions);
    }

    @Override
    public List<PermissionsTreeDTO> getAllTreePermissionsList(Long userId) {
        // 查询出当前用户拥有的所有角色
        List<SysPermissionEntity> dbFirstPermissions = sysPermissionMapper
                .selectPermissionByParentId(NumberUtils.LONG_ZERO);
        if (CollectionUtils.isEmpty(dbFirstPermissions)) {
            return Lists.newArrayList();
        }
        List<PermissionsTreeDTO> permissionsTreeDTOList = SysPermissionsConvert.INSTANCE
                .toPermissionsDTOList(dbFirstPermissions);
        if (CollectionUtils.isEmpty(permissionsTreeDTOList)) {
            return Lists.newArrayList();
        }
        for (PermissionsTreeDTO item : permissionsTreeDTOList) {
            Long id = item.getPermissionId();
            item.setChildren(doTreeNode(id));
        }
        return permissionsTreeDTOList;
    }

    @Override
    public PageResult<PermissionsTreeDTO> getPagePermissionsList(PermissionPageRequest request) {
        Assert.notNull(request, "参数为空！");
        // 第一层数据转换
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<SysPermissionEntity> dbFirstPermissions = sysPermissionMapper
                .selectPermissionByParentId(NumberUtils.LONG_ZERO);
        if (CollectionUtils.isEmpty(dbFirstPermissions)) {
            return PageResult.ofEmpty();
        }
        List<PermissionsTreeDTO> permissionsTreeDTOList = SysPermissionsConvert.INSTANCE
                .toPermissionsDTOList(dbFirstPermissions);
        if (CollectionUtils.isEmpty(permissionsTreeDTOList)) {
            return PageResult.ofEmpty();
        }
        for (PermissionsTreeDTO item : permissionsTreeDTOList) {
            Long id = item.getPermissionId();
            item.setChildren(doTreeNode(id));
        }
        return PageResult.of(dbFirstPermissions, permissionsTreeDTOList);
    }

    public List<ComponentVO> getMenuByParentId(Long parentId) {
        Assert.notNull(parentId, "父类ID不能为空！");
        final List<SysPermissionEntity> dbFirstPermissions = sysPermissionMapper.selectPermissionByParentId(parentId);
        if (CollectionUtils.isEmpty(dbFirstPermissions)) {
            return Lists.newArrayList();
        }
        return ComponentConvert.INSTANCE.toComponentDTOList(dbFirstPermissions);
    }

    @Override
    public List<ComponentVO> getMenu(Long userId) {
        // 第一层数据转换
        final List<ComponentVO> firstList = getMenuByParentId(NumberUtils.LONG_ZERO);
        if (CollectionUtils.isEmpty(firstList)) {
            return Lists.newArrayList();
        }
        for (ComponentVO item : firstList) {
            Long id = item.getPermissionId();
            // 数据第一层都是Layout
            item.setComponent("Layout");
            item.setChildren(doComponentTreeNode(id));
        }
        return firstList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addPermissions(PermissionRequest permissionRequest) {
        Assert.notNull(permissionRequest.getParentId(), "父类ID不能为空！");
        Assert.notNull(permissionRequest.getPermissionType(), "权限类型不能为空！");
        if (StringUtils.isBlank(permissionRequest.getPermissionName())) {
            throw new ParamsException("名称不能为空！");
        }
        if (StringUtils.isBlank(permissionRequest.getPermissionCode())) {
            throw new ParamsException("权限编码不能为空！");
        }
        // 权限名称已存在
        Integer countName = sysPermissionMapper.selectCountPermissionName(permissionRequest.getPermissionName());
        if (countName != null && countName > NumberUtils.INTEGER_ZERO) {
            throw new BizException(40301, "权限名称已存在！");
        }
        // 权限编码已存在
        Integer countCode = sysPermissionMapper.selectCountPermissionCode(permissionRequest.getPermissionCode());
        if (countCode != null && countCode > NumberUtils.INTEGER_ZERO) {
            throw new BizException(40302, "权限编码已存在！");
        }
        // 类型：0：目录；1：菜单；2：按钮
        if (permissionRequest.getPermissionType() == PermissionTypeEnums.DIRECTORY.getCode()) {
            handleDirectory(permissionRequest);
        } else if (permissionRequest.getPermissionType() == PermissionTypeEnums.MENU.getCode()) {
            handleMenu(permissionRequest);
        } else if (permissionRequest.getPermissionType() == PermissionTypeEnums.BUTTON.getCode()) {
            handleButton(permissionRequest);
        } else {
            throw new BizException("不支持该类型！");
        }
        final SysPermissionEntity insertEntity = SysPermissionsConvert.INSTANCE
                .toSysPermissionsEntity(permissionRequest);
        return sysPermissionMapper.insert(insertEntity) > 0;
    }

    @Override
    public Boolean deletePermissions() {
        return null;
    }

    private void handleMenu(PermissionRequest permissionRequest) {
    }

    private void handleDirectory(PermissionRequest permissionRequest) {

    }

    private void handleButton(PermissionRequest permissionRequest) {

    }

    /**
     * 递归构建树形结构
     *
     * @param parentId 父id
     * @return {@link List}<{@link PermissionsTreeDTO}>
     */
    public List<PermissionsTreeDTO> doTreeNode(Long parentId) {
        // 递归退出条件
        final List<PermissionsTreeDTO> firstLevelList = getPermissionsByParentId(parentId);
        if (CollectionUtils.isEmpty(firstLevelList)) {
            return Lists.newArrayList();
        }
        for (PermissionsTreeDTO item : firstLevelList) {
            final Long id = item.getPermissionId();
            if (id == null) {
                continue;
            }
            if (id.equals(item.getParentId())) {
                throw new IllegalArgumentException("parentId和自身ID相等");
            }
            item.setChildren(doTreeNode(item.getPermissionId()));
        }
        return firstLevelList;

    }

    /**
     * 递归构建树形结构
     *
     * @param parentId 父id
     * @return {@link List}<{@link PermissionsTreeDTO}>
     */
    public List<ComponentVO> doComponentTreeNode(Long parentId) {
        // 递归退出条件
        final List<ComponentVO> firstLevelList = getMenuByParentId(parentId);
        if (CollectionUtils.isEmpty(firstLevelList)) {
            return Lists.newArrayList();
        }
        for (ComponentVO item : firstLevelList) {
            final Long id = item.getPermissionId();
            if (id == null) {
                continue;
            }
            if (id.equals(item.getParentId())) {
                throw new IllegalArgumentException("parentId和自身ID相等");
            }
            item.setChildren(doComponentTreeNode(id));
        }
        return firstLevelList;

    }

    /**
     * 构建树
     *
     * @param treeNodes 树节点
     * @return {@link List}<{@link PermissionsTreeDTO}>
     */
    public static List<PermissionsTreeDTO> buildTree(List<PermissionsTreeDTO> treeNodes) {
        if (CollectionUtils.isEmpty(treeNodes)) {
            return Lists.newArrayList();
        }
        List<PermissionsTreeDTO> result = Lists.newArrayList();

        // list 转 map
        Map<Long, PermissionsTreeDTO> nodeMap = new LinkedHashMap<>(treeNodes.size());
        for (PermissionsTreeDTO treeNode : treeNodes) {
            nodeMap.put(treeNode.getPermissionId(), treeNode);
        }

        Collection<PermissionsTreeDTO> values = nodeMap.values();

        for (PermissionsTreeDTO node : values) {
            PermissionsTreeDTO parent = nodeMap.get(node.getParentId());
            if (parent != null && !(node.getPermissionId().equals(parent.getPermissionId()))) {
                parent.getChildren().add(node);
                continue;
            }

            result.add(node);
        }

        return result;
    }

}
